###############################################################################
## Tucan Project
##
## Copyright (C) 2008-2010 Fran Lupion crak@tucaneando.com
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
###############################################################################

import os
import sys
import optparse
import unittest
import logging
import traceback
import json
import urllib
import webbrowser
import time

sys.path.append(os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "../")))
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "../default_plugins/")))

from core.url_open import URLOpen
from core.service_config import ServiceConfig

LEVEL = {"DEBUG": logging.DEBUG, "INFO": logging.INFO, "WARNING": logging.WARNING, "ERROR": logging.ERROR, "CRITICAL": logging.CRITICAL}

TEST_PREFIX = "test_"
TEST_SUFIX = ".py"
PATH_SEPARATOR = "/"

class Suite:
	""""""
	def __init__(self, path, method=None):
		""""""
		self.loader = unittest.TestLoader()
		self.test_files = []		
		if not path:
			path = os.listdir(".")
			
		self.recursive_walk_suites(path)
		
		if method:
			suite = []
			for tmp_suite in self.test_files:
				suite.append("%s.%s" %(tmp_suite, method))
		else:
			suite = self.test_files
		self.loaded_suite = self.loader.loadTestsFromNames(suite)

	def recursive_walk_suites(self, names, parent=""):
		""""""
		if not isinstance(names, list):
			if os.path.basename(names).startswith(TEST_PREFIX) and names.endswith(TEST_SUFIX):
				module_name = ".".join(names.split(TEST_SUFIX)[0].split(PATH_SEPARATOR))
				self.test_files.append(module_name)
		elif names:
			for path in names:
				path = os.path.join(parent, path)
				if os.path.isdir(path) and not os.path.basename(path).startswith("."):
					self.recursive_walk_suites(os.listdir(path), path)
				else:
					self.recursive_walk_suites(path)

class Result(unittest._TextTestResult):

	__super_init = unittest._TextTestResult.__init__
	__super_startTest = unittest._TextTestResult.startTest
	__super_printErrors = unittest._TextTestResult.printErrors
	
	def __init__(self, stream, descriptions, verbosity, total):
		self.__super_init(stream, descriptions, verbosity)
		self.results = []
		self.current_results = []
		self.plugin = None
		self.success = True
		self.total = total
		self.run = 0
		
	def startTest(self, test):
		unittest._TextTestResult.startTest(self, test)
		self.run += 1
		plugin = self.getDescription(test).split(" (")[1].split(")")[0]
		self.plugin = plugin if not self.plugin else self.plugin
		if plugin != self.plugin:
			self.results.append([self.plugin, self.success, self.current_results])
			self.current_results = []
			self.success = True
			self.plugin = plugin
			
	def stopTest(self, test):
		unittest._TextTestResult.stopTest(self, test)
		if(self.total==self.run):
			self.results.append([self.plugin, self.success, self.current_results])
		
	def addError(self, test, err):
		unittest._TextTestResult.addError(self, test, err)
		self.success = False
		method = self.getDescription(test).split(" (")[0]
		error = "".join(traceback.format_exception(*err))
		self.current_results.append([method,error])
		
	def addFailure(self, test, err):
		unittest._TextTestResult.addFailure(self, test, err)
		self.success = False
		method = self.getDescription(test).split(" (")[0]
		error = "".join(traceback.format_exception(*err))
		self.current_results.append([method,error])

class Runner(unittest.TextTestRunner):

	def _makeResult(self, total):
		return Result(self.stream, self.descriptions, self.verbosity, total)

	def run(self, suite):
		result = self._makeResult(suite.countTestCases())
		suite(result)
		answer = None
		while (answer not in ["y","n"]):
			print "\nWould you like to send these results ? [y/n]"
			answer = raw_input()
		if answer == "y":
			self.send_results(result.results)
		return result
		
	def send_results(self, plugins):
		results = []
		service = {'name':'','plugins':[],'update':''}
		for index, plugin in enumerate(plugins):
			tmp = plugin[0].split("test_")[1].split(".")[0]
			if tmp != service["name"]:
				if index:
					results.append(service)
				CONF_PATH = "../default_plugins/%s" % tmp
				config = ServiceConfig(os.path.join(os.path.dirname(sys.argv[0]), CONF_PATH))
				service = {'name':tmp,'plugins':[],'update':config.get_update()}
			service["plugins"].append(plugin)
			if index == len(plugins)-1:
				results.append(service)
		js = json.dumps(results)

		#The request has to be a POST one due to the ammount of informations
		#The following code opens a page in a browser to ensure authentication
		#Based on : http://goo.gl/aV30R
		url = "http://localhost:8080/tests"
		content = """
		<script src='http://www.google.com/jsapi'></script>
		<script>
			google.load('jquery', '1.6.0');
		</script>

		<script>
			$(document).ready(function() {{$("#form").submit(); }});
		</script>

		<form id='form' action='{0}' method='POST' />
			<input type="hidden" name="results" value='{1}' />
		</form>
		"""
		
		with open('temp_file.html', "w") as file:
			file.write(content.format(url, js))
			file.close()
			webbrowser.open(os.path.abspath(file.name))
			time.sleep(1)
			os.remove(os.path.abspath(file.name))


if __name__ == '__main__':	
	parser = optparse.OptionParser()
	parser.add_option("-l", "--logging", dest="level", default="", help="set logger LEVEL (default=ERROR)", metavar="LEVEL")
	parser.add_option("-m", "--test-method", dest="method", default="", help="only test METHOD", metavar="METHOD")
	parser.add_option("-v", "--verbosity", dest="verbosity", default=1, help="set verbosity LEVEL (default=1)", metavar="LEVEL")
	options, args = parser.parse_args()

	logging.basicConfig(level=LEVEL.get(options.level.upper(), logging.ERROR))
	
	try:
		s = Suite(args, options.method)
	except Exception, e:
		print "Failed to load suite: %s" % e
	else:
		Runner(verbosity=int(options.verbosity)).run(s.loaded_suite)
